package slices

// list容器的增强版，增加筛选过滤、反转、判断条件、遍历执行等方法
// 注意：所有函数都不会修改原来的切片，都是创建一个新的切片来操作。

import (
	"golang.org/x/exp/constraints"
)

func init() {

}

type CompareFunc[T comparable] func(e1 T, e2 T) bool
type FilterFunc[T any] func(e T) bool
type FilterMapFunc[T any, T2 any] func(e T) (T2, bool)
type FoldFunc[T any, T2 any] func(e T, acc T2) T2
type ForeachFunc[T any] func(v T)
type MapFunc[T any, T2 any] func(v T) T2

// 创建包含参数的切片，支持任意个相同类型的参数：
//
//	slice := New(1, 2, 3, 4)
func New[T any](vals ...T) []T {
	slice := make([]T, 0, 4)
	slice = append(slice, vals...)
	return slice
}

// 从一个切片复制出一个新的切片
func Clone[T any](slice1 []T) []T {
	slice := make([]T, 0, len(slice1))
	slice = append(slice, slice1...)
	return slice
}

// 创建一个由 N 个元素 v 组成的切片：
//
//	slice := Duplicate(5, 1)  // 结果为： [1 1 1 1 1]
func Duplicate[T any](N int, v T) []T {
	slice := make([]T, 0, 4)
	for i := 0; i < N; i++ {
		slice = append(slice, v)
	}
	return slice
}

// 生成一个由 From 到 To 的切片，递增值是 Incr 的序列正数列表，From、To可以是负数：
//
//	slice := Sequence(0, 6, 2)  // 结果为： [0 2 4 6]
func Sequence[T constraints.Integer](From T, To T, Incr T) []T {
	slice := make([]T, 0, int((To-From)/Incr)+1)
	for i := From; (Incr > 0 && i <= To) || (Incr < 0 && i >= To); i += Incr {
		slice = append(slice, i)
	}
	return slice
}

// 判断切片里的所有元素是否都满足条件
func All[T any](slice []T, f FilterFunc[T]) bool {
	for _, v := range slice {
		if !f(v) {
			return false
		}
	}
	return true
}

// 判断切片里的是否存在某一个元素满足条件
func Any[T any](slice []T, f FilterFunc[T]) bool {
	for _, v := range slice {
		if f(v) {
			return true
		}
	}
	return false
}

// 统计满足条件的元素
func Count[T any](slice1 []T, f FilterFunc[T]) int {
	n := 0
	for _, v := range slice1 {
		if f(v) {
			n += 1
		}
	}
	return n
}

// 删除切片的一个元素
func Delete[T comparable](slice1 []T, v1 T) []T {
	slice := Clone(slice1)
	for i, v := range slice {
		if v == v1 {
			slice = append(slice[:i], slice[i+1:]...)
			break
		}
	}
	return slice
}

// 删除切片的所有值等于 v 的元素
func DeleteAll[T comparable](slice1 []T, v T) []T {
	slice := Clone(slice1)
	for i := 0; i < len(slice); {
		if slice[i] == v {
			slice = append(slice[:i], slice[i+1:]...)
		} else {
			i++
		}
	}
	return slice
}

// 删除切片的第一个元素
func DropFirst[T any](slice1 []T) []T {
	slice := Clone(slice1)
	slice = append(slice[0:0], slice[1:]...)
	return slice
}

// 删除切片的最后一个元素
func DropLast[T any](slice1 []T) []T {
	slice := Clone(slice1)
	slice = append(slice[:len(slice)-1], []T{}[:]...)
	return slice
}

// 从头到尾依次删除满足条件的元素，直到遇到不满足条件的元素为止。
func DropWhile[T any](slice1 []T, f FilterFunc[T]) []T {
	slice := Clone(slice1)
	for i := 0; i < len(slice); {
		if f(slice[i]) {
			slice = append(slice[:i], slice[i+1:]...)
		} else {
			break
		}
	}
	return slice
}

// 保留满足条件的元素，删除不满足条件的元素。
func Filter[T any](slice1 []T, f FilterFunc[T]) []T {
	slice := Clone(slice1)
	for i := 0; i < len(slice); {
		if !f(slice[i]) {
			slice = append(slice[:i], slice[i+1:]...)
		} else {
			i++
		}
	}
	return slice
}

// 过滤并映射操作符合函数条件的元素
func FilterMap[T any, T2 any](slice1 []T, f FilterMapFunc[T, T2]) []T2 {
	slice := make([]T2, 0, len(slice1))
	for _, v := range slice1 {
		r, ok := f(v)
		if ok {
			slice = append(slice, r)
		}
	}
	return slice
}

// 返回元素在切片中的位置（索引），找不到返回-1
func FindIndex[T comparable](slice []T, v T) int {
	for i := 0; i < len(slice); i++ {
		if slice[i] == v {
			return i
		}
	}
	return -1
}

// 返回第一个元素
func First[T any](slice []T) T {
	if len(slice) == 0 {
		panic("First error: slice is empty")
	}
	return slice[0]
}

// 将 2 层嵌套切片转为单层切片（减少一层，多层切片可以多次调用）
func Flatten[T any](slice1 [][]T) []T {
	slice := make([]T, 0, len(slice1))
	for _, v := range slice1 {
		slice = append(slice[:], v[:]...)
	}
	return slice
}

// 从头到尾依次对所有元素递归调用函数 f，并将累计结果 acc 返回。
func FoldL[T any, T2 any](slice []T, f FoldFunc[T, T2], acc T2) T2 {
	for i := 0; i < len(slice); i++ {
		acc = f(slice[i], acc)
	}
	return acc
}

// 从尾到头依次对所有元素递归调用函数 f，并将累计结果 acc 返回。
func FoldR[T any, T2 any](slice []T, f FoldFunc[T, T2], acc T2) T2 {
	for i := len(slice) - 1; i >= 0; i-- {
		acc = f(slice[i], acc)
	}
	return acc
}

// 从头到尾依次对所有元素执行函数 f。
func Foreach[T any](slice []T, f ForeachFunc[T]) {
	for _, v := range slice {
		f(v)
	}
}

// 判断是否与另一个切片拥有相同的元素
func IsEqual[T comparable](a, b []T) bool {
	if len(a) != len(b) {
		return false
	}

	for i, v := range a {
		if v != b[i] {
			return false
		}
	}

	return true
}

// 返回最后一个元素
func Last[T any](slice []T) T {
	if len(slice) == 0 {
		panic("Last error: slice is empty")
	}
	return slice[len(slice)-1]

}

// 将切片中的每个元素去在 f 中执行，将所有执行结果组成一个新的切片
func Map[T any, T2 any](slice1 []T, f MapFunc[T, T2]) []T2 {
	slice2 := make([]T2, 0, len(slice1))
	for _, v := range slice1 {
		slice2 = append(slice2, f(v))
	}
	return slice2
}

// 返回数值最大的一个元素
func Max[T constraints.Ordered](slice []T) T {
	var now T = slice[0]
	for _, v := range slice {
		if now < v {
			now = v
		}
	}

	return now
}

// 合并所有切片成一个切片
func Merge[T any](slices ...[]T) []T {
	Len := 0
	for _, slice1 := range slices {
		Len += len(slice1)
	}
	slice := make([]T, 0, Len)
	for _, slice1 := range slices {
		slice = append(slice, slice1...)
	}
	return slice
}

// 判断 v 是否存在切片中
func Member[T comparable](slice []T, v1 T) bool {
	for _, v := range slice {
		if v1 == v {
			return true
		}
	}
	return false
}

// 返回数值最小的一个元素
func Min[T constraints.Ordered](slice []T) T {
	var now T = slice[0]
	for _, v := range slice {
		if now > v {
			now = v
		}
	}
	return now
}

// 取第N个元素，0 为第一个，正数从头开始，负数从尾开始
func Nth[T any](slice []T, i int) T {
	if len(slice) == 0 {
		panic("Nth error: slice is empty")
	}

	if i >= 0 && i < len(slice) {
		return slice[i]
	} else if len(slice)-i > 0 {
		return slice[len(slice)+i]
	}
	panic("Nth error: index is out of range")
}

// 根据条件将切片里的元素分成满足条件的和不满足条件的
func Partition[T any](slice []T, f FilterFunc[T]) ([]T, []T) {
	slice1 := make([]T, 0, len(slice))
	slice2 := make([]T, 0, len(slice))
	for _, v := range slice {
		if f(v) {
			slice1 = append(slice1, v)
		} else {
			slice2 = append(slice2, v)
		}
	}
	return slice1, slice2
}

// 添加一个元素到切片的前面
func PushFront[T comparable](slice1 []T, v1 T) []T {
	slice := make([]T, 0, len(slice1)+1)
	slice = append(slice, v1)
	slice = append(slice, slice1...)
	return slice
}

// 添加一个元素到切片的最后
func PushBack[T comparable](slice1 []T, v1 T) []T {
	slice := make([]T, 0, len(slice1)+1)
	slice = append(slice, slice1...)
	slice = append(slice, v1)
	return slice
}

// 反转切片的元素
func Reverse[T any](slice1 []T) []T {
	slice := Clone(slice1)
	for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {
		slice[i], slice[j] = slice[j], slice[i]
	}
	return slice
}

// 按照排序函数来排序切片，排序函数 f 为 nil 时使用默认的排序函数
func Sort[T constraints.Ordered](slice1 []T) []T {
	slice := Clone(slice1)
	n := len(slice)
	for i := 0; i < n; i++ {
		for j := i + 1; j < n; j++ {
			if slice[i] > slice[j] {
				slice[i], slice[j] = slice[j], slice[i]
			}
		}
	}
	return slice
}

// 将切片拆成两个切片返回，一个包含前面 N 个元素，另一个包含剩下的元素
func Split[T any](slice []T, N int) ([]T, []T) {
	slice1 := make([]T, 0, len(slice))
	slice2 := make([]T, 0, len(slice))
	return append(slice1[:], slice[0:N]...), append(slice2[:], slice[N:]...)
}

// 将切片拆成两个切片返回
// 从头到尾依次复制满足条件的元素到第一个切片，直到遇到不满足条件的元素为止，剩下的复制到第二切片
func SplitWith[T any](slice []T, f FilterFunc[T]) ([]T, []T) {
	slice1 := make([]T, 0, len(slice))
	slice2 := make([]T, 0, len(slice))
	for i, v := range slice {
		if !f(v) {
			return append(slice1[:], slice[0:i]...), append(slice2[:], slice[i:]...)
		}
	}
	return append(slice1[:], slice[:]...), make([]T, 0, 2)
}

// 返回一个从 Len 开始，个数为 Len 的子切片。
func Sublist[T any](slice1 []T, Start int, Len int) []T {
	slice := make([]T, 0, Len)
	return append(slice[:], slice1[Start:Start+Len]...)
}

// 删除切片在另一切片里出现的元素
func Subtract[T comparable](slice []T, slice2 []T) []T {
	for _, v := range slice2 {
		slice = Delete(slice, v)
	}
	return slice
}

// 计算切片里每个元素的总和
func Sum[T constraints.Integer | constraints.Float](slice []T) T {
	var acc T = 0
	for _, v := range slice {
		acc += v
	}
	return acc
}

// 从头到尾依次保留满足条件的元素，直到遇到不满足条件的元素为止。
func TakeWhile[T any](slice1 []T, f FilterFunc[T]) []T {
	slice := make([]T, 0, len(slice1))
	for i := 0; i < len(slice1); i++ {
		if !f(slice1[i]) {
			slice = append(slice[:0], slice1[0:i]...)
			break
		}
	}
	return slice
}

// 对切片进行去重处理
func Unique[T comparable](slice1 []T) []T {
	slice := Clone(slice1)
	for i := 0; i < len(slice); i++ {
		for j := i + 1; j < len(slice); {
			if slice[j] == slice[i] {
				slice = append(slice[:j], slice[j+1:]...)
			} else {
				j++
			}
		}
	}
	return slice
}
